﻿using Daphne.GameShared;
using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Daphne.MiddleLayerModule
{
    /// <summary>
    /// Class implementing the business logic of game-board editor
    /// </summary>
    internal class GameEditor: IGameEditor
    {
        /// <summary>
        /// Reference to the gameboard
        /// </summary>
        [Dependency]
        protected IGameBoardForEditor GameBoard
        { get; set; }

        /// <summary>
        /// Undo / Redo stacks
        /// </summary>
        private Stack<BitBoard> _positionsUndo;
        private Stack<BitBoard> _positionsRedo;

        /// <summary>
        /// Constructor
        /// </summary>
        public GameEditor()
        {
            _positionsUndo = new Stack<BitBoard>();
            _positionsRedo = new Stack<BitBoard>();
        }

        /// <summary>
        /// Editor mode started - clear internal variables
        /// </summary>
        public void NotifyEditModeStarted()
        {
            _positionsUndo.Clear();           
            _positionsRedo.Clear();
        }

        /// <summary>
        /// Puts a figure onto a field
        /// </summary>
        public void PlaceFigure(Position pos, enumFigureType figureType)
        {
            SaveToUndoStack();
            GameBoard.PlaceFigure(pos, figureType);
        }

        /// <summary>
        /// Clears the given field
        /// </summary>
        public void ClearField(Position pos)
        {
            SaveToUndoStack();
            GameBoard.ClearField(pos);
        }

        /// <summary>
        /// Clears the board
        /// </summary>
        public void ClearBoard()
        {
            SaveToUndoStack();
            GameBoard.ClearBoard();
        }

        /// <summary>
        /// Setups the starting position
        /// </summary>
        public void SetStartupPosition()
        {
            SaveToUndoStack();
            GameBoard.SetStartupPosition();
        }

        /// <summary>
        /// Sets the side to move
        /// </summary>
        /// <param name="stm"></param>
        public void SetSTM(enumFigureColor stm)
        {
            GameBoard.SetSTM(stm);
        }

        /// <summary>
        /// Returns the side to move
        /// </summary>
        /// <returns></returns>
        public enumFigureColor GetSTM()
        {
            return GameBoard.GetSTM();
        }

        /// <summary>
        /// Not implemented for now - FUTURE USE
        /// </summary>
        public void SetFENPosition(string fen)
        {
            // TO-DO: save to stack
            throw new NotImplementedException();
        }

        /// <summary>
        /// Performs undo operation
        /// </summary>
        public void Undo()
        {
            BitBoard bb = GameBoard.PackPosition();
            _positionsRedo.Push(bb);
            GameBoard.UnpackPosition(_positionsUndo.Pop());
        }

        /// <summary>
        /// Performs redo operation
        /// </summary>
        public void Redo()
        {
            BitBoard bb = GameBoard.PackPosition();
            _positionsUndo.Push(bb);
            GameBoard.UnpackPosition(_positionsRedo.Pop());
        }

        /// <summary>
        /// Saves current board situation to the undo stack
        /// </summary>
        private void SaveToUndoStack()
        {
            _positionsUndo.Push(GameBoard.PackPosition());
            _positionsRedo.Clear();
        }

        /// <summary>
        /// Returns whether we can undo
        /// </summary>
        public bool CanUndo()
        {
            return _positionsUndo.Count > 0;
        }

        /// <summary>
        /// Returns whether we can perform
        /// redo operation 
        /// </summary>
        public bool CanRedo()
        {
            return _positionsRedo.Count > 0;
        }

        /// <summary>
        /// Restores the board situation before 
        /// the beginning of edit mode
        /// </summary>
        public void RestorePreviousPosition()
        {
            while (CanUndo())
                Undo();
        }

        /// <summary>
        /// Returns the field color
        /// </summary>
        public enumFigureColor GetFieldColor(Position pos)
        {
            return GameBoard.GetFieldColor(pos);
        }

        /// <summary>
        /// Returns figure at given field
        /// </summary>
        public enumFigureType GetField(Position pos)
        {
            return GameBoard.GetField(pos);
        }
    }
}
